关于日期:使用Python获取本月的最后一天

您所在的位置:网站首页 python relativedelta函数 关于日期:使用Python获取本月的最后一天

关于日期:使用Python获取本月的最后一天

2024-06-16 17:23| 来源: 网络整理| 查看: 265

是否有一种方法可以使用Python的标准库轻松确定(即一个函数调用)给定月份的最后一天?

如果标准库不支持,那么dateutil包是否支持此功能?

相关讨论 我是唯一一个认为你在要求Python的最后一天的人吗?:d[20081124从回复移动到评论---在引入评论系统之前发布了原始回复]

我之前在查看日历模块的文档时没有注意到这一点,但是一个名为Monthrange的方法提供了以下信息:

monthrange(year, month)     Returns weekday of first day of the month and number of days in month, for the specified year and month.

1234567>>> import calendar >>> calendar.monthrange(2002,1) (1, 31) >>> calendar.monthrange(2008,2) (4, 29) >>> calendar.monthrange(2100,2) (0, 28)

所以:

1calendar.monthrange(year, month)[1]

似乎是最简单的方法。

很明显,monthrange也支持闰年:

123>>> from calendar import monthrange >>> monthrange(2012, 2) (2, 29)

我以前的回答仍然有效,但显然是次优的。

相关讨论 这不是原始问题的正确答案!如果一个月的最后一天是周六/周日呢? @马赫迪:没错,第二个数字是"月份天数"=="最后一天",不管是哪一天。 对于1800年2月,这是错误的一天。我不明白 @剑1号,我认为用公历的规则来回答,这是正确的。

如果不想导入calendar模块,简单的两步功能还可以是:

12345import datetime def last_day_of_month(any_day):     next_month = any_day.replace(day=28) + datetime.timedelta(days=4)  # this will never fail     return next_month - datetime.timedelta(days=next_month.day)

输出:

123456789101112131415>>> for month in range(1, 13): ...     print last_day_of_month(datetime.date(2012, month, 1)) ... 2012-01-31 2012-02-29 2012-03-31 2012-04-30 2012-05-31 2012-06-30 2012-07-31 2012-08-31 2012-09-30 2012-10-31 2012-11-30 2012-12-31

编辑:请参阅@blair conrad的答案以获得更清洁的解决方案

1234>>> import datetime >>> datetime.date (2000, 2, 1) - datetime.timedelta (days = 1) datetime.date(2000, 1, 31) >>> 相关讨论 事实上,我会称之为清洁剂,除了12月份当today.month + 1 == 13和你得到一个ValueError时它失效的事实。 你可以通过使用(today.month % 12) + 1来解决这个问题,因为12 % 12给出0

编辑:看看我的其他答案。它有一个比这个更好的实现,我把它留在这里,以防有人有兴趣看到一个可能"滚动您自己的"计算器。

@约翰·米利金给出了一个很好的答案,另外还有计算下个月第一天的复杂度。

以下不是特别优雅,但要想找出任何给定日期所在月份的最后一天,您可以尝试:

1234567891011def last_day_of_month(date):     if date.month == 12:         return date.replace(day=31)     return date.replace(month=date.month+1, day=1) - datetime.timedelta(days=1) >>> last_day_of_month(datetime.date(2002, 1, 17)) datetime.date(2002, 1, 31) >>> last_day_of_month(datetime.date(2002, 12, 9)) datetime.date(2002, 12, 31) >>> last_day_of_month(datetime.date(2008, 2, 14)) datetime.date(2008, 2, 29)

相关讨论 这听起来很傻,但我如何得到第一天的一个月类似这样。 不是总是1吗? 是的,但我很困惑,我在找这样的东西:开始日期=日期(datetime.now().year,datetime.now().month,1) 啊。today = datetime.date.today(); start_date = today.replace(day=1)。您应该避免调用datetime.now两次,以防您在12月31日午夜之前调用它,然后在午夜之后调用它。你将得到2016-01-01而不是2016-12-01或2017-01-01。 这很容易理解并返回一个日期时间实例,在许多情况下这可能很有用。另一个好处是,如果输入date是datetime.date、datetime.datetime和pandas.Timestamp的实例,它就可以工作。

使用dateutil.relativedelta非常简单(pip的包python-datetutil)。day=31将始终返回该月的最后一天。

例子:

123456from datetime import datetime from dateutil.relativedelta import relativedelta date_in_feb = datetime.datetime(2013, 2, 21) print datetime.datetime(2013, 2, 21) + relativedelta(day=31)  # End-of-month >>> datetime.datetime(2013, 2, 28, 0, 0)

相关讨论 我个人更喜欢相对论英语(月=1,秒=1),这似乎更明显。 你错了。datetime(2014, 2, 1) + relativedelta(days=31)给了datetime(2014, 3, 4, 0, 0)… 你用days=代替day= @文斯皮瑟在闰年工作?

使用relativedelta,您将得到如下的最后一个月日期:

12from dateutil.relativedelta import relativedelta last_date_of_month = datetime(mydate.year, mydate.month, 1) + relativedelta(months=1, days=-1)

这样做的目的是得到一个月的第一天,然后用relativedelta提前一个月,然后再回来一天,这样你就可以得到你想要的月的最后一天。

另一种解决方案是这样做:

12345678910111213from datetime import datetime def last_day_of_month(year, month):    """ Work out the last day of the month"""     last_days = [31, 30, 29, 28, 27]     for i in last_days:         try:             end = datetime(year, month, i)         except ValueError:             continue         else:             return end.date()     return None

使用如下函数:

123456789>>> >>> last_day_of_month(2008, 2) datetime.date(2008, 2, 29) >>> last_day_of_month(2009, 2) datetime.date(2009, 2, 28) >>> last_day_of_month(2008, 11) datetime.date(2008, 11, 30) >>> last_day_of_month(2008, 12) datetime.date(2008, 12, 31)

相关讨论 太复杂了,打破了第三条Python禅的规则。 次优解,但有效。不值得-3。+ 1;

12from datetime import timedelta (any_day.replace(day=1) + timedelta(days=32)).replace(day=1) - timedelta(days=1)

相关讨论 这就是bug的来源;)1月31日试试。 @李尔茨:对我有用。当你尝试时会发生什么? 将任何一天设置为1月31日,这将不起作用。 它起作用了。任何一天是1月31日,我们用1替换当天,所以1月1日,加上32天,我们得到2月2日,再次替换为1日,我们得到2月1日。减去一天,我们得到1月31日。我不知道是什么问题。你哪天来?

123456789101112>>> import datetime >>> import calendar >>> date  = datetime.datetime.now() >>> print date 2015-03-06 01:25:14.939574 >>> print date.replace(day = 1) 2015-03-01 01:25:14.939574 >>> print date.replace(day = calendar.monthrange(date.year, date.month)[1]) 2015-03-31 01:25:14.939574

如果您愿意使用外部库,请访问http://crsmithdev.com/arrow/

然后,您可以通过以下方式获得每月的最后一天:

12import arrow arrow.utcnow().ceil('month').date()

这将返回一个日期对象,然后可以对其进行操作。

为了得到这个月的最后一个日期,我们这样做:

123from datetime import date, timedelta import calendar last_day = date.today().replace(day=calendar.monthrange(date.today().year, date.today().month)[1])

现在,为了解释我们在这里所做的工作,我们将把它分为两部分:

首先是得到本月使用Monthrange的天数,Blair Conrad已经提到了他的解决方案:

1calendar.monthrange(date.today().year, date.today().month)[1]

第二个是获取最后一个日期本身,这是我们在替换的帮助下完成的,例如

1234>>> date.today() datetime.date(2017, 1, 3) >>> date.today().replace(day=31) datetime.date(2017, 1, 31)

当我们按照上面提到的方法组合它们时,我们得到了一个动态解。

相关讨论 尽管此代码可能有助于解决问题,但它不能解释为什么和/或如何回答问题。提供这种额外的背景将显著提高其长期教育价值。请编辑您的答案以添加解释,包括哪些限制和假设适用。 这似乎是最直接的……如果你想给它两行,你可以得到一个很好的date.replace(day=day),所以每个人都知道发生了什么。

1234567import datetime now = datetime.datetime.now() start_month = datetime.datetime(now.year, now.month, 1) date_on_next_month = start_month + datetime.timedelta(35) start_next_month = datetime.datetime(date_on_next_month.year, date_on_next_month.month, 1) last_day_month = start_next_month - datetime.timedelta(1)

最简单的方法(不必导入日历)是获取下个月的第一天,然后从中减去一天。

1234567import datetime as dt from dateutil.relativedelta import relativedelta thisDate = dt.datetime(2017, 11, 17) last_day_of_the_month = dt.datetime(thisDate.year, (thisDate + relativedelta(months=1)).month, 1) - dt.timedelta(days=1) print last_day_of_the_month

输出:

1datetime.datetime(2017, 11, 30, 0, 0)

PS:与import calendar方法相比,此代码运行得更快;请参见以下内容:

1234567891011121314151617181920import datetime as dt import calendar from dateutil.relativedelta import relativedelta someDates = [dt.datetime.today() - dt.timedelta(days=x) for x in range(0, 10000)] start1 = dt.datetime.now() for thisDate in someDates:     lastDay = dt.datetime(thisDate.year, (thisDate + relativedelta(months=1)).month, 1) - dt.timedelta(days=1) print ('Time Spent= ', dt.datetime.now() - start1) start2 = dt.datetime.now() for thisDate in someDates:     lastDay = dt.datetime(thisDate.year,                           thisDate.month,                           calendar.monthrange(thisDate.year, thisDate.month)[1]) print ('Time Spent= ', dt.datetime.now() - start2)

输出:

12Time Spent=  0:00:00.097814 Time Spent=  0:00:00.109791

此代码假定您需要一个月最后一天的日期(即,不只是dd部分,而是整个yyyymmdd日期)

相关讨论 你为什么不想这样做? 因为它更快。我已经修改了我上面的答案,将其包括在内。 @vishal您的概念是正确的,但下面的行不是:``dt.datetime(thisdate.year,(thisdate+relativedelta(months=1)).month,1)-dt.timedelta(days=1)````特别是当月份在年底时。改为尝试``上个月的最后一个日期`=第一个月的第一个日期`+relativedelta(months=1)-relativedelta(days=1)``

对我来说,这是最简单的方法:

123456selected_date = date(some_year, some_month, some_day) if selected_date.month == 12: # December      last_day_selected_month = date(selected_date.year, selected_date.month, 31) else:      last_day_selected_month = date(selected_date.year, selected_date.month + 1, 1) - timedelta(days=1)

在python 3.7中,有未记录的calendar.monthlen(year, month)函数:

123456>>> calendar.monthlen(2002, 1) 31 >>> calendar.monthlen(2008, 2) 29 >>> calendar.monthlen(2100, 2) 28

它相当于记录的calendar.monthrange(year, month)[1]呼叫。

你可以自己计算结束日期。简单的逻辑是从下个月的开始日期减去一天。:)

所以写一个自定义方法,

123456789101112131415161718import datetime def end_date_of_a_month(date):     start_date_of_this_month = date.replace(day=1)     month = start_date_of_this_month.month     year = start_date_of_this_month.year     if month == 12:         month = 1         year += 1     else:         month += 1     next_month_start_date = start_date_of_this_month.replace(month=month, year=year)     this_month_end_date = next_month_start_date - datetime.timedelta(days=1)     return this_month_end_date

打电话,

1end_date_of_a_month(datetime.datetime.now().date())

它将返回这个月的结束日期。将任何日期传递给此函数。返回该月的结束日期。

这是另一个答案。不需要额外的包裹。

1datetime.date(year + int(month/12), month%12+1, 1)-datetime.timedelta(days=1)

得到下个月的第一天,从中减去一天。

我喜欢这边

12345import datetime import calendar date=datetime.datetime.now() month_end_date=datetime.datetime(date.year,date.month,1) + datetime.timedelta(days=calendar.monthrange(date.year,date.month)[1] - 1)

使用熊猫!

123456789def isMonthEnd(date):     return date + pd.offsets.MonthEnd(0) == date isMonthEnd(datetime(1999, 12, 31)) True isMonthEnd(pd.Timestamp('1999-12-31')) True isMonthEnd(pd.Timestamp(1965, 1, 10)) False

相关讨论 您还可以使用pd.series.dt.is_month_end链接实现 pandas datetime对象具有特定的方法:now=datetime.datetime.now(); pd_now = pd.to_datetime(now); print(pd_now.days_in_month)。

这并不能解决主要问题,但是一个很好的办法就是使用calendar.monthcalendar,它返回一个日期矩阵,以星期一为第一列,星期日为最后一列。

12345678# Some random date. some_date = datetime.date(2012, 5, 23) # Get last weekday last_weekday = np.asarray(calendar.monthcalendar(some_date.year, some_date.month))[:,0:-2].ravel().max() print last_weekday 31

整个[0:-2]的事情就是把周末专栏删掉,然后扔掉。月份之外的日期用0表示,因此max有效地忽略了它们。

使用numpy.ravel并不是绝对必要的,但我不喜欢仅仅依赖于一个惯例,即如果不告诉哪个轴需要计算,numpy.ndarray.max会使数组变平。

你可以用relativedeltahttps://dateutil.readthedocs.io/en/stable/relativedelta.html网站埃多克斯1〔6〕这将给你最后一天。

如果你想做你自己的小功能,这是一个很好的起点:

1234567def eomday(year, month):    """returns the number of days in a given month"""     days_per_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]     d = days_per_month[month - 1]     if month == 2 and (year % 4 == 0 and year % 100 != 0 or year % 400 == 0):         d = 29     return d

为此,您必须了解闰年的规则:

每四年 除了每100年 但每400年 相关讨论 当然,但是系统库已经有了这些数据,如果规则被法令更改,那么更新库就成了别人的问题。 嗯,可能,但可能性很小,即使-它只会在大约2000年内咬你一口…en.wikipedia.org/wiki/Gregorian_日历准确性 这些规则在过去的500年里是行不通的,我不相信它们会在未来的数千年里继续存在,

123import calendar from time import gmtime, strftime calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1]

输出:

131

这将打印当前月份的最后一天。在本例中,是2016年5月15日。因此,您的输出可能会有所不同,但输出的天数将与当前月份的天数相同。如果你想通过每天运行cron作业来检查一个月的最后一天,那就太好了。

所以:

12345import calendar from time import gmtime, strftime lastDay = calendar.monthrange(int(strftime("%Y", gmtime())), int(strftime("%m", gmtime())))[1] today = strftime("%d", gmtime()) lastDay == today

输出:

1False

除非是这个月的最后一天。

如果在日期范围内传递,则可以使用此选项:

123456def last_day_of_month(any_days):     res = []     for any_day in any_days:         nday = any_day.days_in_month -any_day.day         res.append(any_day + timedelta(days=nday))     return res

在下面的代码中,"get-last-day-u of-month(dt)"将给出这个值,日期采用字符串格式,如"yyyy-mm-dd"。

12345678910111213141516import datetime def DateTime( d ):     return datetime.datetime.strptime( d, '%Y-%m-%d').date() def RelativeDate( start, num_days ):     d = DateTime( start )     return str( d + datetime.timedelta( days = num_days ) ) def get_first_day_of_month( dt ):     return dt[:-2] + '01' def get_last_day_of_month( dt ):     fd = get_first_day_of_month( dt )     fd_next_month = get_first_day_of_month( RelativeDate( fd, 31 ) )     return RelativeDate( fd_next_month, -1 )

下面是基于解决方案的python lambdas:

12next_month = lambda y, m, d: (y, m + 1, 1) if m + 1


【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3